#include "unavigationbar.h"
#include "uapplication.h"
#include "ulabel.h"
#include "style/upalette.h"
#include "style/uproxystyle.h"
#include "upushbutton.h"

#include <QVBoxLayout>
#include <QButtonGroup>
#include <QStyleOptionButton>
#include <QPainterPath>
#include <QPainter>
#include <QAction>

UNavigationButton::UNavigationButton(const QString text, QWidget* parent) : QPushButton(text, parent)
{
    init();
}

UNavigationButton::UNavigationButton(QWidget* parent) : QPushButton(parent)
{
    init();
}

UNavigationButton::~UNavigationButton()
{
}

void UNavigationButton::setCloseButtonMargins(int margins)
{
    setProperty("CloseButtonMargins", margins);
    layout->setContentsMargins(9, 0, margins, 0);
    update();
}

void UNavigationButton::setButtonType(const ButtonType &type)
{
    int margins = (ButtonType::ButtonNoBackground == type) ? 4 : 12;
    setCloseButtonMargins(margins);
    setProperty("ButtonType", type);
    update();
}

void UNavigationButton::setBackGroudMargins(const QMargins &margins)
{
    if (contentMargins != margins)
    {
        contentMargins = margins;
        update();
    }
}

void UNavigationButton::init()
{
    UPushButton* closeButton = new UPushButton(this);
    closeButton->setButtonType(ButtonType::ButtonNoBackground);
    closeButton->setIcon(QIcon::fromTheme("close"));
    closeButton->setFixedSize(18, 18);
    closeButton->setRadius(9);
    layout = new QHBoxLayout;
    layout->setContentsMargins(9, 0, 12, 0);
    setProperty("CloseButtonMargins", 12);
    layout->addStretch();
    layout->addWidget(closeButton);
    layout->setAlignment(closeButton, Qt::AlignVCenter);
    setLayout(layout);
    connect(closeButton, &UPushButton::clicked, this, &UNavigationButton::closed);
}

QPainterPath UNavigationButton::selectPath(const QRect &rect)
{
    QPainterPath path;
    const qreal radius = 8;

    path.moveTo(rect.topLeft().x() + radius, rect.top());
    path.arcTo(QRect(rect.topLeft(), QSize(radius * 2, radius * 2)), 90, 90);
    path.lineTo(rect.left(), rect.bottom() - radius);
    path.arcTo(QRect(QPoint(rect.left() - (radius * 2), rect.bottom() - radius * 2), QSize(radius * 2, radius * 2)), 0, -90);
    path.lineTo(rect.right(), rect.bottom());
    path.lineTo(rect.right(), rect.top() + radius);
    path.arcTo(rect.right() - radius * 2, rect.top(), radius * 2, radius * 2, 0.0f, 90.0f);
    path.lineTo(rect.topLeft().x() + radius, rect.top());

    QPainterPath path1;
    path1.moveTo(rect.right() + radius, rect.bottom());
    path1.lineTo(rect.right(), rect.bottom());
    path1.lineTo(rect.right(), rect.bottom() - radius);
    path1.arcTo(QRect(QPoint(rect.right(), rect.bottom() - radius * 2), QSize(radius * 2, radius * 2)), 180, 90);
    path = path.united(path1);

    return path;
}

void UNavigationButton::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event)
    QStyleOptionButton btn;
    initStyleOption(&btn);
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

    drawBackGroud(&painter, &btn);

    auto textRect = uApp->style()->subElementRect(UProxyStyle::SE_PushButtonContents, &btn, this);
    uint alignment = uApp->style()->visualAlignment(btn.direction, Qt::AlignLeft | Qt::AlignVCenter);
    QPixmap pix;
    if (!btn.icon.isNull())
    {
        textRect.setX(textRect.x() + 8);
        pix = UProxyStyle::getIconPixmap(btn.state, btn.icon, btn.iconSize);
        uApp->style()->drawItemPixmap(&painter, textRect, alignment, pix);
        if (btn.direction == Qt::RightToLeft)
            textRect.setRight(textRect.right() - btn.iconSize.width() - 4);
        else
            textRect.setLeft(textRect.left() + btn.iconSize.width() + 4);
    }
    textRect.setWidth(textRect.width() - (16 + property("CloseButtonMargins").toInt()));
    if (!btn.text.isEmpty())
    {
        QString text = btn.fontMetrics.elidedText(btn.text, Qt::ElideMiddle, textRect.width());
        painter.setPen(uApp->applicationPalette()->color(QPalette::ButtonText));
        painter.drawText(textRect, Qt::TextSingleLine | Qt::AlignLeft | Qt::AlignVCenter, text);
    }
}

void UNavigationButton::drawBackGroud(QPainter* painter, const QStyleOptionButton* option)
{
    QPainterPath path;
    QColor color = Qt::transparent;
    if (isChecked())
    {
        path = checkedPath();
        color = palette().color(QPalette::Highlight);
    }
    else
    {
        if (option->state & QStyle::State_Enabled)
        {
            if (option->state & QStyle::State_MouseOver)
            {
                path = hoverPath();
                color = palette().color(QPalette::Button).darker(120);
            }
        }
    }
    if (!path.isEmpty())
    {
        painter->fillPath(path, color);
    }
}

QPainterPath UNavigationButton::checkedPath()
{
    const qreal radius = 8;
    QRect rect = QRect(radius, 0, width() - 2 * radius, height());
    QPainterPath path;
    if (ButtonType::ButtonNormal == this->property("ButtonType").toInt())
    {
        path = selectPath(rect);
    }
    return path;
}

QPainterPath UNavigationButton::hoverPath()
{
    const qreal radius = 8;
    QRect rect = QRect(radius, 0, width() - 2 * radius, height());
    QPainterPath path;
    if (ButtonType::ButtonNormal == this->property("ButtonType").toInt())
    {
        path.addRoundedRect(rect, 8, 8);
    }
    else
    {
        auto hoverRect = this->rect().adjusted(contentMargins.left(), contentMargins.top(), contentMargins.right(), contentMargins.bottom());
        path.addRoundedRect(hoverRect, 8, 8);
    }
    return path;
}

class UNavigationBarPrivate
{
public:
    UNavigationBarPrivate(UNavigationBar* q) : q_ptr(q) {}
    ~UNavigationBarPrivate() {}

    void init();

    void initConnection();

private:
    Q_DECLARE_PUBLIC(UNavigationBar)
    Q_DISABLE_COPY(UNavigationBarPrivate)
    UNavigationBar* const q_ptr = nullptr;

    QHBoxLayout* mainLayout = nullptr;
    QHBoxLayout* contentLayout = nullptr;
    QButtonGroup* buttonGroup = nullptr;
    ULabel *leftLabel = nullptr;
    UPushButton *addButton = nullptr;
};

void UNavigationBarPrivate::init()
{
    Q_Q(UNavigationBar);
    mainLayout = new QHBoxLayout;
    mainLayout->setContentsMargins(6, 0, 6, 0);
    contentLayout = new QHBoxLayout;
    contentLayout->setSpacing(6);
    buttonGroup = new QButtonGroup(q);
    leftLabel = new ULabel(q);
    addButton = new UPushButton(q);
    addButton->setFixedSize(30, 30);
    addButton->setRadius(15);
    addButton->setButtonType(ButtonType::ButtonNoBackground);
    addButton->setIcon(QIcon::fromTheme("utk_add"));
    mainLayout->addWidget(leftLabel);
    mainLayout->addLayout(contentLayout);
    mainLayout->addWidget(addButton);
    q->setLayout(mainLayout);
    initConnection();
}

void UNavigationBarPrivate::initConnection()
{
    Q_Q(UNavigationBar);

    q->connect(addButton, &UPushButton::clicked, q, &UNavigationBar::addButtonClicked);
}

UNavigationBar::UNavigationBar(QWidget* parent) : UWidget(parent)
    , d_ptr(new UNavigationBarPrivate(this))
{
    Q_D(UNavigationBar);
    d->init();
}

UNavigationBar::~UNavigationBar()
{
}

void UNavigationBar::setAction(const QAction &action)
{
    Q_D(UNavigationBar);
    if (!action.icon().isNull())
    {
        d->leftLabel->setFixedSize(36, 36);
        d->leftLabel->setIcon(action.icon());
    }
    if (!action.text().isEmpty())
    {
        d->leftLabel->setText(action.text());
    }
}

void UNavigationBar::addButton(const QIcon &icon, const QString &text, Qt::Alignment alignment)
{
    Q_D(UNavigationBar);
    UNavigationButton* button = new UNavigationButton(text, this);
    button->setIcon(icon);
    addButton(button, alignment);
}

void UNavigationBar::addButton(UNavigationButton* button, Qt::Alignment alignment)
{
    Q_D(UNavigationBar);
    if (nullptr == button)
    {
        return;
    }
    button->setButtonType(ButtonType::ButtonNoBackground);
    button->setCheckable(true);
    button->setToolTip(button->text());
    button->setMinimumHeight(36);
    d->contentLayout->addWidget(button);
    int count = d->buttonGroup->buttons().size();
    d->buttonGroup->addButton(button, count);
    connect(button, &UNavigationButton::closed, this, &UNavigationBar::onCloseButton);
    connect(button, &UNavigationButton::clicked, this, [ this ]()
    {
        this->update();
    });
}

void UNavigationBar::removeButton(UNavigationButton* button)
{
    Q_D(UNavigationBar);
    if (nullptr == button)
    {
        return;
    }
    d->buttonGroup->removeButton(button);
    d->contentLayout->removeWidget(button);
    emit buttonRemoved(button->text());
    button->setParent(nullptr);
    button->deleteLater();
}

void UNavigationBar::paintEvent(QPaintEvent* event)
{
    Q_D(UNavigationBar);
    UWidget::paintEvent(event);
    QPainterPath path;
    if (auto button = qobject_cast<UNavigationButton*>(d->buttonGroup->checkedButton()))
    {
        path = button->selectPath(button->geometry());
    }
    if (!path.isEmpty())
    {
        QPainter painter(this);
        painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
        painter.fillPath(path, palette().color(QPalette::Highlight));
    }
}

void UNavigationBar::onCloseButton()
{
    Q_D(UNavigationBar);
    removeButton(qobject_cast<UNavigationButton*>(sender()));
}
